#pragma once

#include <iostream>
#include <sstream>
#include <string>
#include <list>

#include "dbcore.h"
#include "datastore2.h"
#include "dbmsException.h"

#define TRUE 1
#define FALSE 0

// Buf instances (types)
#define END		-1
#define ERR		0
#define NUM		1
#define ID		2
#define CNST	3
#define RES		2
#define SYMB	5

// Column Type
#define CTINT		11
#define CTVCHAR		12
#define CTKEY		13

// Factor types
#define VAR			22
#define EXPR		23

/*
namespace expression
{ */


//															TEXT

	class cText
	{
		std::string msg;
		int currPos;
		int prevPos;

	public:
		cText();

		int setMsg(char *sentence);
		char nextChar();
		int ungetChar();
		void savePos();

		std::string exceptionP(char * msg);
	};


//															EXPRESSION

	class cToken;
	class cTerm;
	class cExpression;

	class cVariable							// Variable
	{
		int varType;
		std::string colName;
		std::string varStr;
		double varValue;

	public:
		int setType(int type);
		int setStr(std::string str);
		int setColName(std::string str);
		int setValue(double val);

		int getType();
		std::string getStr();
		std::string getColName();
		double getValue();
	};

	class cExpression_list					// Expression list
	{
		cExpression *expr;
		char oper;

	public:
		cExpression_list() {expr = NULL; oper = NULL;};
		~cExpression_list() {if (expr != NULL) delete expr; expr = NULL;};

		int readExpr_list(cText *text, cToken *token);
		cVariable execExpr_list(std::vector< std::vector<std::string> > data, int line);

		char getOper();
	};


	class cTerm_list						// Term list
	{
		cTerm *term;
		char oper;

	public:
		cTerm_list() {term = NULL; oper = NULL;};
		~cTerm_list() {if (term != NULL) delete term; term = NULL;};

		int readTerm_list(cText *text, cToken *token);
		cVariable execTerm_list(std::vector< std::vector<std::string> > data, int line);

		char getOper();
	};


	class cFactor							// Factor
	{
		int type;
		cVariable var;
		cExpression *expr;

		cVariable getCell(std::string column, std::vector< std::vector<std::string> > data, int line);

	public:
		cFactor() {expr = NULL; type = NULL;};
		~cFactor() {if (expr != NULL) delete expr; expr = NULL;};

		int readFactor(cText *text, cToken *token);
		cVariable execFactor(std::vector< std::vector<std::string> > data, int line);
	};


	class cTerm								// Term
	{
		cFactor *factor;
		cTerm_list *term_list;
	public:
		cTerm() {factor = NULL; term_list = NULL;};
		~cTerm() {if (factor != NULL) delete factor; if (term_list != NULL) delete term_list; factor = NULL; term_list = NULL;};

		int readTerm(cText *text, cToken *token);
		cVariable execTerm(std::vector< std::vector<std::string> > data, int line);
	};


	class cExpression						//Expression
	{
		cTerm *term;
		cExpression_list *expr_list;

	public:
		cExpression() {term = NULL; expr_list = NULL;};
		~cExpression() {if (term != NULL) delete term; if (expr_list != NULL) delete expr_list; term = NULL; expr_list = NULL;};

		int readExpr(cText *text, cToken *token);
		cVariable execExpr(std::vector< std::vector<std::string> > data, int line);
	};


	class cCondition						// Condition
	{
		cExpression *left;
		cExpression *right;
		std::string operand;
		cCondition *and;
		cCondition *or;

	public:
		cCondition() {left = NULL; right = NULL; and = NULL; or = NULL;};
		~cCondition() {if(left!=NULL) delete left; if(right!=NULL) delete right; if(and!=NULL) delete and; if(or!=NULL) delete or;};

		int readCondition(cText *text, cToken *token);
		std::vector< std::vector<std::string> > execCondition(std::vector< std::vector<std::string> > data);
	};


	class cConjunction;
	class cSentence;

	class cSentence_list					// Sentence list
	{
		cSentence *sentence;

	public:
		cSentence_list() {sentence = NULL;};
		~cSentence_list() {if (sentence != NULL) delete sentence; sentence = NULL;};

		int readSentence_list(cText *text, cToken *token);
		std::vector< std::vector<std::string> > execSentence_list(std::vector< std::vector<std::string> > data);
	};


	class cConjunction_list						// Conjunction list
	{
		cConjunction *conjunction;

	public:
		cConjunction_list() {conjunction = NULL;};
		~cConjunction_list() {if (conjunction != NULL) delete conjunction; conjunction = NULL;};

		int readConjunction_list(cText *text, cToken *token);
		std::vector< std::vector<std::string> > execConjunction_list(std::vector< std::vector<std::string> > data);
	};


	class cUnit							// Unit
	{
		cSentence *sentence;
		cCondition *condition;

	public:
		cUnit() {sentence = NULL;};
		~cUnit() {if (sentence != NULL) delete sentence; sentence = NULL;};

		int readUnit(cText *text, cToken *token);
		std::vector< std::vector<std::string> > execUnit(std::vector< std::vector<std::string> > data);
	};


	class cConjunction								// Conjunction
	{
		cUnit *unit;
		cConjunction_list *conjunction_list;
	public:
		cConjunction() {unit = NULL; conjunction_list = NULL;};
		~cConjunction() {if (unit != NULL) delete unit; if (conjunction_list != NULL) delete conjunction_list; unit = NULL; conjunction_list = NULL;};

		int readConjunction(cText *text, cToken *token);
		std::vector< std::vector<std::string> > execConjunction(std::vector< std::vector<std::string> > data);
	};


	class cSentence						// Sentence
	{
		cConjunction *conjunction;
		cSentence_list *sentence_list;

	public:
		cSentence() {conjunction = NULL; sentence_list = NULL;};
		~cSentence() {if (conjunction != NULL) delete conjunction; if (sentence_list != NULL) delete sentence_list; conjunction = NULL; sentence_list = NULL;};

		int readSentence(cText *text, cToken *token);
		std::vector< std::vector<std::string> > execSentence(std::vector< std::vector<std::string> > data);
	};

	
//															SELECT

	class cSelect
	{
		std::vector<std::string> fields;
		std::vector<std::string> tables;
		cSentence *condition;

		int readFields(cText *text, cToken *token);
		int readTables(cText *text, cToken *token);

	public:
		cSelect() {condition = NULL; fields.clear(); tables.clear();};
		~cSelect() {if (condition != NULL) delete condition;};

		int readSelect(cText *text, cToken *token);

		std::string execSelect();
	};


//															INSERT

	class cInsert
	{
		std::vector<std::string> fields;
		std::string table;
		std::vector<std::string> values;

		int countFields;
		int countValues;

		int readFields(cText *text, cToken *token);
		int readTable(cText *text, cToken *token);
		int readValues(cText *text, cToken *token);

	public:
		cInsert() {fields.clear(); table.clear(); countFields = 0; countValues = 0;};
		~cInsert() {};

		int readInsert(cText *text, cToken *token);

		std::string execInsert();
	};


//															DROP

	class cDrop
	{
		std::string table;

	public:
		cDrop() {table.clear();};
		~cDrop() {};

		int readDrop(cText *text, cToken *token);

		std::string execDrop();
	};


//															CREATE

	class cCreate
	{
		std::string table;
		vector<std::string> columns;
		vector<std::string> types;

	public:
		cCreate() {table.clear();};
		~cCreate() {};

		int readCreate(cText *text, cToken *token);

		std::string execCreate();
	};


//															DELETE

	class cDelete
	{
		std::string table;
		cCondition *condition;

	public:
		cDelete() {condition = NULL; table.clear();};
		~cDelete() {if (condition != NULL) delete condition;};

		int readDelete(cText *text, cToken *token);

		std::string execDelete();
	};


//															UPDATE

	class cUpdate
	{
		std::string table;
		cCondition *condition;
		std::vector<std::string> column;

		int readValues(cText *text, cToken *token);

	public:
		cUpdate() {condition = NULL; table.clear();};
		~cUpdate() {if (condition != NULL) delete condition;};

		int readUpdate(cText *text, cToken *token);

		std::string execUpdate();
	};

	
//															HELPME

	class cHelp
	{
	public:
		cHelp() {};
		~cHelp() {};

		int readHelp(cText *text, cToken *token);
		std::string execHelp();
	};


//															TREE

	class cTree
	{
		cSelect *select;
		cInsert *insert;
		cDrop *drop;
		cCreate *create;
		cDelete *del;
		cUpdate *update;
		cHelp *help;

	public:
		cTree() {select = NULL; insert = NULL; drop = NULL; create = NULL; del = NULL; update = NULL;};
		~cTree() {if (select != NULL) delete select; if (insert != NULL) delete insert; if (drop != NULL) delete drop; if (create != NULL) delete create; if (del != NULL) delete del;if (update != NULL) delete update;};

		int readTree(cText *text, cToken *token);

		std::string execTree();
	};


//															TOKEN

	class cToken					// Temporate depository while reading next Token
	{
		// Buffer
		int isBufEmpty;
		int bufType;
		std::string bufStr;
		double bufValue;

		int readToken(cText *text);	// Read next Token

		int resWord(std::string buf);
		std::string upReg(std::string data);

	public:
		cToken() {isBufEmpty = 1;};

		int nextToken(cText *text);	// Get next Token

		int pushBack();		// Push back current token, like it wasn't read

		// Buffer content operations
		int getBufType();
		std::string getBufStr();
		double getBufValue();
	};
//}